﻿/**************************************************************
 * Copyright www.eastmoney.com. All rights reserved.
 * 
 * Author: gt1987(guitao@eastmoney.com) 
 * Create Date: 2021/4/13 14:31:56
 * Description: 
 *          
 * Revision History:
 *      Date         Author               Description
 *              
***************************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Collection.Sample
{
    public class ThreadsSample
    {

        private AutoResetEvent resetEvent_A = new AutoResetEvent(false);
        private AutoResetEvent resetEvent_B = new AutoResetEvent(true);

        private int num = 1;

        /// <summary>
        /// 通过2个线程顺序循环打印0~100
        /// </summary>
        /// <param name="threadCounts"></param>
        public void Run()
        {
            var task1 = Task.Run(() =>
            {
                while (true)
                {
                    resetEvent_B.WaitOne();
                    if (num > 100) break;
                    PrintNum(num++);
                    resetEvent_A.Set();
                }
            });
            var task2 = Task.Run(() =>
            {
                while (true)
                {
                    resetEvent_A.WaitOne();
                    if (num > 100) break;
                    PrintNum(num++);
                    resetEvent_B.Set();
                }
            });

            Task.WaitAll(task1, task2);
        }

        /// <summary>
        /// 通过N个线程顺序循环打印0~100
        /// </summary>
        /// <param name="threadCounts"></param>
        public void Run(int threadCounts)
        {
            Dictionary<int, AutoResetEvent> resetEvents_dic = new Dictionary<int, AutoResetEvent>();
            //Queue<AutoResetEvent> resetEvents_q = new Queue<AutoResetEvent>();
            List<Task> tasks = new List<Task>();
            for (int i = threadCounts; i > 0; i--)
            {
                //init reset event
                var state = i == threadCounts ? true : false;
                var resetEvent = new AutoResetEvent(state);
                resetEvents_dic.Add(i, resetEvent);
            }
            for (int i = 1; i < threadCounts + 1; i++)
            {
                var resetEvent = resetEvents_dic[i];
                //init task
                tasks.Add(Task.Factory.StartNew((state) =>
                {
                    var threadIndex = (int)state;
                    var currentResetEvent = resetEvents_dic[threadIndex];
                    var lastResetEvent = threadIndex - 1 < 1 ? resetEvents_dic[threadCounts] : resetEvents_dic[threadIndex - 1];
                    while (true)
                    {
                        lastResetEvent.WaitOne();
                        if (num > 100) break;
                        PrintNum(num++);
                        currentResetEvent.Set();
                    }
                }, i));
            }

            Task.WaitAll(tasks.ToArray());
        }


        private void PrintNum(int num)
        {
            var threadId = Thread.CurrentThread.ManagedThreadId;
            Console.WriteLine($"【{threadId}】 {num}");
        }
    }

    public class SemaphoreSample
    {
        private Semaphore semaphore = new Semaphore(5, 5);

        public void Run()
        {
            List<Task> tasks = new List<Task>();
            for (int i = 0; i < 20; i++)
            {
                tasks.Add(Task.Factory.StartNew((o) =>
                {
                    var threadId = o.ToString();
                    Console.WriteLine($"【{threadId}】等待信号量。");
                    if (semaphore.WaitOne())
                    {
                        Console.WriteLine($"【{threadId}】获取到信号量。");
                        Thread.Sleep(new Random().Next(1000, 3000));
                        semaphore.Release();
                        Console.WriteLine($"【{threadId}】释放信号量。");
                    }
                }, i));
            }

            Task.WaitAll(tasks.ToArray());
        }
    }
}
